﻿#include "C3fdSolveControlWidget.h"
#include "ui_C3fdSolveControlWidget.h"
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QFileDialog>

namespace MainWidget
{

	C3fdSolveControlWidget::C3fdSolveControlWidget(QTreeWidgetItem *item, bool isFirst, QWidget *parent)
		: QWidget(parent), m_Ui(new Ui::C3fdSolveControlWidget), m_IsFirstWorkCondition(isFirst)
	{
		m_Ui->setupUi(this);

		m_Project = Common::C3fdProject::instance();
		m_CurrentCase = m_Project->getCurrentCase();
		if (m_CurrentCase != nullptr && item != nullptr)
		{
			m_CurrentWorkCondition = m_CurrentCase->getWorkConditions().value(item->text(0));
		}
		connect(&m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessOutput()));
		connect(&m_Process, SIGNAL(readyReadStandardError()), this, SLOT(readAllStandardErrorSlot()));
		connect(&m_Process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));

		if (m_CurrentWorkCondition != nullptr)
		{
			m_Ui->dsb_RotationSpeed->blockSignals(true);
			m_Ui->dsb_InletTemperature->blockSignals(true);
			m_Ui->dsb_InletPressure->blockSignals(true);
			m_Ui->dsb_InletAirflowAngle->blockSignals(true);
			m_Ui->dsb_OutletPressure->blockSignals(true);
			m_Ui->sb_StartRotationSpeed->blockSignals(true);
			m_Ui->sb_IterativeSteps->blockSignals(true);

			m_Ui->dsb_RotationSpeed->setRange(0, DBL_MAX);
			m_Ui->dsb_InletTemperature->setRange(0, DBL_MAX);
			m_Ui->dsb_InletPressure->setRange(0, DBL_MAX);
			m_Ui->dsb_InletAirflowAngle->setRange(0, DBL_MAX);
			m_Ui->dsb_OutletPressure->setRange(0, DBL_MAX);
			m_Ui->sb_StartRotationSpeed->setRange(0, INT_MAX);
			m_Ui->sb_IterativeSteps->setRange(0, INT_MAX);

			m_Ui->dsb_RotationSpeed->setValue(m_CurrentWorkCondition->getRotationSpeed());
			m_Ui->dsb_InletTemperature->setValue(m_CurrentWorkCondition->getIntletTemp());
			m_Ui->dsb_InletPressure->setValue(m_CurrentWorkCondition->getInletPress());
			m_Ui->dsb_InletAirflowAngle->setValue(m_CurrentWorkCondition->getAirflowAngle());
			m_Ui->dsb_OutletPressure->setValue(m_CurrentWorkCondition->getOutletPress());
			m_Ui->sb_StartRotationSpeed->setValue(m_CurrentWorkCondition->getStartRotationSpeed());
			m_Ui->sb_IterativeSteps->setValue(m_CurrentWorkCondition->getInterativeStep());

			m_Ui->dsb_OutletPressure->setStyleSheet("background:#fff;");
			m_Ui->sb_StartRotationSpeed->setStyleSheet("background:#fff;");
			m_Ui->sb_IterativeSteps->setStyleSheet("background:#fff;");
			m_Ui->sb_Cores->setStyleSheet("background:#fff;");

			m_Ui->dsb_RotationSpeed->blockSignals(false);
			m_Ui->dsb_InletTemperature->blockSignals(false);
			m_Ui->dsb_InletPressure->blockSignals(false);
			m_Ui->dsb_InletAirflowAngle->blockSignals(false);
			m_Ui->dsb_OutletPressure->blockSignals(false);
			m_Ui->sb_StartRotationSpeed->blockSignals(false);
			m_Ui->sb_IterativeSteps->blockSignals(false);
		}

		if (!m_IsFirstWorkCondition)
		{
			m_Ui->dsb_RotationSpeed->setReadOnly(true);
			m_Ui->dsb_RotationSpeed->setEnabled(false);
			m_Ui->dsb_RotationSpeed->setToolTip(tr("Can only be set in the first working condition"));
			m_Ui->dsb_InletTemperature->setReadOnly(true);
			m_Ui->dsb_InletTemperature->setEnabled(false);
			m_Ui->dsb_InletTemperature->setToolTip(tr("Can only be set in the first working condition"));
			m_Ui->dsb_InletPressure->setReadOnly(true);
			m_Ui->dsb_InletPressure->setEnabled(false);
			m_Ui->dsb_InletPressure->setToolTip(tr("Can only be set in the first working condition"));
			m_Ui->dsb_InletAirflowAngle->setReadOnly(true);
			m_Ui->dsb_InletAirflowAngle->setEnabled(false);
			m_Ui->dsb_InletAirflowAngle->setToolTip(tr("Can only be set in the first working condition"));
		}
	}

	C3fdSolveControlWidget::~C3fdSolveControlWidget()
	{
		delete m_Ui;
	}

	bool C3fdSolveControlWidget::copyMeshInputs(QString meshPath, QString inputPath)
	{
		if (inputPath.isEmpty())
		{
			return false;
		}
		QFile file;
		// 从mesh文件夹拷贝文件
		QStringList filesNeedCopyFromMeshDir = {
			m_Project->getMeshUsedForSolverFileName(),
			m_Project->getGeomInfoOfBladeFileName()};
		for (auto f : filesNeedCopyFromMeshDir)
		{
			if (file.exists(inputPath + f))
			{
				if (!file.remove(inputPath + f))
				{
					return false;
				}
			}
			if (file.exists(meshPath + f))
			{
				if (!file.copy(meshPath + f, inputPath + f))
				{
					QMessageBox::critical(this, tr("Error Info"), QString(tr("Failed to copy file: %1!").arg(f)));
					return false;
				}
			}
			else
			{
				QMessageBox::critical(this, tr("Error Info"), QString(tr("File not found: %1!").arg(f)));
				return false;
			}
		}
		return true;
	}

	bool C3fdSolveControlWidget::generateControlInput(QString inputPath)
	{
		QFile controlFile(inputPath + m_Project->getSolverControlFileName());
		if (!controlFile.open(QFile::WriteOnly | QIODevice::Truncate | QIODevice::Text))
		{
			return false;
		}
		QTextStream control(&controlFile);
		control << "***********************************************************\n";
		control << "*** Define the folder in which outputed files are saved ***\n";
		control << "***********************************************************\n";
		control << "'OUTPUT/'        Baseline Folder for the outputed files\n";
		control << "***********************************************************\n";
		control << "**** Definition of run-time task of the current mission ***\n";
		control << "***********************************************************\n";
		control << "3                LOGTASK\n";
		control << "***********************************************************\n";
		control << "**************  Iteration control parameters  *************\n";
		control << "***********************************************************\n";
		control << "0                NPOLD\n";
		control << "8000             NPASSM\n";
		control << "100              NSAVE\n";
		control << "1                NSHOW\n";
		control << "0                NP1ORD\n";
		control << "0                NSTYLE\n";
		control << "1                LRESID\n";
		control << "1                LPRSCREEN\n";
		control << "***********************************************************\n";
		control << "*****  Parameter governing low-speed preconditioning  *****\n";
		control << "***********************************************************\n";
		control << "1.0              VMREF\n";
		control << "***********************************************************\n";
		control << "********  Parameters justifying inputed data sets  ********\n";
		control << "***********************************************************\n";
		control << "0                LREADFLOW\n";
		control << "0                LREADFTVS\n";
		control << "0                LREADBCON\n";
		control << "***********************************************************\n";
		control << "*******  parameters for time-accurate calculations  *******\n";
		control << "***********************************************************\n";
		control << "0                NDIVIDE\n";
		control << "0.0              DTPHY\n";
		control << "0                NITPSDN\n";
		control << "0                DTIMRES\n";
		control << "***********************************************************\n";
		control << "*****************  Reference parameters  ******************\n";
		control << "***********************************************************\n";
		control << "288.0            TEMFORRE\n";
		control << "101325.0         PREFORRE\n";
		control << "-1.0             RENFORRE\n";
		control << "0.0              VELFORRE\n";
		control << "***********************************************************\n";
		control << "************  Parameters for fluid properties  ************\n";
		control << "***********************************************************\n";
		control << "1                NLVGAMA\n";
		control << "0.0              ROIL\n";
		control << "1.4              GAMA\n";
		control << "287.06           RGAS\n";
		control << "0.72             CPRL\n";
		control << "0.9              CPRT\n";
		control << "1.71610D-5       VIS0\n";
		control << "273.16D0         TEM0\n";
		control << "124.D0           TEMS\n";
		control << "################# End of inputed parameters ###############\n";
		control.flush();
		controlFile.close();
		return true;
	}

	bool C3fdSolveControlWidget::generateTbmodelInput(QString inputPath)
	{
		QFile TbmodelFile(inputPath + m_Project->getSolverTbmodelFileName());
		if (!TbmodelFile.open(QFile::WriteOnly | QIODevice::Truncate | QIODevice::Text))
		{
			return false;
		}
		QTextStream Tbmodel(&TbmodelFile);
		Tbmodel << "***********************************************************\n";
		Tbmodel << "*** Define some control parameters for turbulence model ***\n";
		Tbmodel << "***********************************************************\n";
		Tbmodel << "0    NLTRIP\n";
		Tbmodel << "1    NLWFUN\n";
		Tbmodel.flush();
		TbmodelFile.close();
		return true;
	}

	bool C3fdSolveControlWidget::generateBoundaryInput(QString inputPath)
	{
		if (m_CurrentCase == nullptr || m_CurrentWorkCondition == nullptr)
		{
			QMessageBox::critical(this, tr("Error Info"), tr("System Error!"));
			return false;
		}
		auto bladeRows = m_CurrentCase->getBladeRows();
		QFile boundaryFile(inputPath + m_Project->getSolverBoundaryFileName());
		if (!boundaryFile.open(QFile::WriteOnly | QIODevice::Truncate | QIODevice::Text))
		{
			return false;
		}
		QTextStream boundary(&boundaryFile);
		boundary << "tandem                                                                                              \n";
		boundary << "**************************************************************************\n";
		boundary << "*******        GEOMETRICAL INFORMATIONS AND ROTATING SPEEDS        *******\n";
		boundary << "******* None of the following parameters are needed to be modified *******\n";
		boundary << "******* except for the rotor rotating speeds.                      *******\n";
		boundary << "**************************************************************************\n";
		boundary << "NUMBER OF FLOW PATHES:   1\n";
		boundary << " \n";
		boundary << "=========================FLOW PATH NO. 1=========================\n";
		boundary << "INLET/OUTLET FEATURE:    1    1\n";
		boundary << "PATCH INFORMATION:\n";
		boundary << "    0\n";
		boundary << "    0\n";
		boundary << QString("NUMBER OF BLADE ROWS OF CURRENT FLOW PATH:    %1\n").arg(bladeRows.size());
		boundary << "-------------------------------------------------------\n";
		boundary << "ROW_NO.   ROTSPEED(rpm)  NCLSHUB  NCLSTIP  LPSHRD  LHUBROT  LCASROT  NSPLIT  NAXISYM  LHUBCAVE  (NOTE)\n";
		QStringList flowPathList = {};
		int indexS = 0, indexR = 1;
		for (int i = 0; i < bladeRows.size(); ++i)
		{
			auto *row = bladeRows.at(i);
			if (row->getType() == Common::BladeRowType::Rotor)
			{
				// 如果第一级是转子，则静子序号从1开始，否则从0开始
				if (i == 0)
				{
					indexS = 1;
				}
				// 转子
				boundary
					<< QString("   %1         %2        0        1        0       1        0        1       %3        0       R %4\n")
						   .arg(row->getRowNum())
						   .arg(m_CurrentWorkCondition->getRotationSpeed())
						   .arg(row->getBladeNum())
						   .arg(indexR);

				flowPathList.push_back(QString("  %1             6000.0               0.0              R %2\n").arg(m_CurrentWorkCondition->getStartRotationSpeed()).arg(indexR));
				++indexR;
			}
			else if (row->getType() == Common::BladeRowType::Stator)
			{
				// 静子
				boundary
					<< QString("   %1         0.0        0        0        0       0        0        1       %2        0       S %3\n")
						   .arg(row->getRowNum())
						   .arg(row->getBladeNum())
						   .arg(indexS++);
			}
		}

		boundary << " \n";
		boundary << "**************************************************************************\n";
		boundary << "********* GOVERNING PARAMETERS FOR THE CONVERGENCE CRITERION *************\n";
		boundary << "**************************************************************************\n";
		boundary << "VARIATION OF MASS FLOW/TOTAL PRESSURE RATIO/EFFICIENCY IN 100 STEPS:      \n";
		boundary << "   0.0000        0.0000          0.0000                                   \n";
		boundary << " \n";
		boundary << "**************************************************************************\n";
		boundary << "*********** PARAMETERS FOR STARTUP AND INLET/OUTLET CONDITIONS ***********\n";
		boundary << "**************************************************************************\n";
		boundary << "TOTAL NUMBER OF STEPS FOR THE START-UP PROCESS:    300                   \n";
		boundary << " \n";
		boundary << "=========================FLOW PATH NO. 1=========================\n";
		boundary << "VROT_FIRST(rpm)  DVROT_INCREASE(rpm)  FMAS_BLEED(kg/s)  ROTOR_NO.\n";
		// boundary << "  3188.0             3000.0               0.0              R 1\n";
		for (auto s : flowPathList)
		{
			boundary << s;
		}
		boundary << " \n";
		boundary << "--------------------------------------------------\n";
		boundary << "HUB/CASING B.L. THICKNESS: (IN FRACTION OF INLET HEIGHT)     \n";
		boundary << "0.0  0.0                                                     \n";
		boundary << "NPINL: (NUMBER OF POINTS TO DEFINE THE PROFILE OF INLET B.C.)\n";
		boundary << "2                                                            \n";
		boundary << "    NP    RSPAN     PTOTAL(Pa)  TTOTAL(K)  ALPHA1(DEGREE)    \n";
		boundary << QString("    01   0.00000   %1     %2       %3             \n").arg(m_CurrentWorkCondition->getInletPress()).arg(m_CurrentWorkCondition->getIntletTemp()).arg(m_CurrentWorkCondition->getAirflowAngle());
		boundary << QString("    02   1.00000   %1     %2       %3             \n").arg(m_CurrentWorkCondition->getInletPress()).arg(m_CurrentWorkCondition->getIntletTemp()).arg(m_CurrentWorkCondition->getAirflowAngle());
		// boundary << "    01   0.00000   101325.0     288.15       0.0             \n";
		// boundary << "    02   1.00000   101325.0     288.15       0.0             \n";
		boundary << " \n";
		boundary << "--------------------------------------------------\n";
		boundary << "NTypeBCout    SPCasing(Pa)      Fmassout(kg/s)     relaxfms\n";
		boundary << "     1         100000.0            1.0               0.5   \n";
		boundary << " \n";
		boundary << "**************************************************************************\n";
		boundary << "** PARAMETERS THAT DEFINE ORDINARY INTER-BLADE ROW BLEEDING CONDITOINS. **\n";
		boundary << "**************************************************************************\n";
		boundary << "NUMBER OF BLEEDING POSITIONS:                                             \n";
		boundary << "0                                                                         \n";
		boundary << "NBL  FMSBL(kg/s)  FLOW_PATH_NO.   AT_EXIT_OF_ROW_NO.  HUB(1)_OR_CASING(2) \n";
		boundary << " 0      0.0            0                 0                  0             \n";
		boundary << " \n";
		boundary << "**************************************************************************\n";
		boundary << "**** PARAMETERS THAT DEFINE BLEEDING WALL CONDITOINS.  USERS NEED TO  ****\n";
		boundary << "**** DEFINE THE ACTUAL BLEEDING POSITION BASED ON COMPUTATIONAL MESH  ****\n";
		boundary << "**************************************************************************\n";
		boundary << "NUMBER OF BLEEDING POSITIONS:                                             \n";
		boundary << "0                                                                         \n";
		boundary << "NBL  FMSBL(kg/s)  LDSURFACE  NBK  IBBL  ITBL  JBBL  JTBL  KBBL  KTBL      \n";
		boundary.flush();
		boundaryFile.close();
		return true;
	}

	bool C3fdSolveControlWidget::generatePerfCurveInput(QString inputPath)
	{
		if (m_CurrentWorkCondition == nullptr)
		{
			return false;
		}

		// 只生成一个工况的文件
		int num = 1;
		QFile perfCurveFile(inputPath + m_Project->getSolverPerfCurveFileName());
		if (!perfCurveFile.open(QFile::WriteOnly | QIODevice::Truncate | QIODevice::Text))
		{
			return false;
		}
		QTextStream perfCurve(&perfCurveFile);
		perfCurve << "TITLE= compressor speed-line calculations." << endl;
		perfCurve << "=====================================================================" << endl;
		perfCurve << " 0    0      NPSEQO  NPASSEQO\n";
		perfCurve << "=====================================================================" << endl;
		perfCurve << " 1   0   1   NPSEQN   LOG_SPECIFY_FOLDERS  LOG-VARIABLE-RPM" << endl;
		perfCurve << "-----------------------------------------------------------------------" << endl;
		perfCurve << "NPSEQ    NPASSN     SPOUT1      r-rpm  " << endl;

		perfCurve << QString("01    %1     %2      %3  ")
						 .arg(m_CurrentWorkCondition->getInterativeStep())
						 .arg(m_CurrentWorkCondition->getOutletPress())
						 .arg(m_CurrentWorkCondition->getRotationSpeed())
				  << endl;
		perfCurve << "==========================================================================" << endl;
		perfCurve.flush();
		perfCurveFile.close();
		return true;
	}

	void C3fdSolveControlWidget::on_dsb_RotationSpeed_editingFinished()
	{
		auto speed = m_Ui->dsb_RotationSpeed->value();
		if (m_CurrentWorkCondition != nullptr && !qFuzzyCompare(m_CurrentWorkCondition->getRotationSpeed(), speed))
		{
			// m_CurrentWorkCondition->setRotationSpeed(speed);
			if (m_CurrentCase != nullptr)
			{
				auto wcs = m_CurrentCase->getWorkConditions();
				for (auto k : wcs.keys())
				{
					wcs[k]->setRotationSpeed(speed);
				}
			}
		}
	}

	void C3fdSolveControlWidget::on_dsb_InletTemperature_editingFinished()
	{
		auto inTemp = m_Ui->dsb_InletTemperature->value();
		if (m_CurrentWorkCondition != nullptr && !qFuzzyCompare(m_CurrentWorkCondition->getIntletTemp(), inTemp))
		{
			// m_CurrentWorkCondition->setIntletTemp(inTemp);
			if (m_CurrentCase != nullptr)
			{
				auto wcs = m_CurrentCase->getWorkConditions();
				for (auto k : wcs.keys())
				{
					wcs[k]->setIntletTemp(inTemp);
				}
			}
		}
	}

	void C3fdSolveControlWidget::on_dsb_InletPressure_editingFinished()
	{
		auto inPress = m_Ui->dsb_InletPressure->value();
		if (m_CurrentWorkCondition != nullptr && !qFuzzyCompare(m_CurrentWorkCondition->getInletPress(), inPress))
		{
			// m_CurrentWorkCondition->setInletPress(inPress);
			if (m_CurrentCase != nullptr)
			{
				auto wcs = m_CurrentCase->getWorkConditions();
				for (auto k : wcs.keys())
				{
					wcs[k]->setInletPress(inPress);
				}
			}
		}
	}

	void C3fdSolveControlWidget::on_dsb_InletAirflowAngle_editingFinished()
	{
		auto inAngle = m_Ui->dsb_InletAirflowAngle->value();
		if (m_CurrentWorkCondition != nullptr && !qFuzzyCompare(m_CurrentWorkCondition->getAirflowAngle(), inAngle))
		{
			// m_CurrentWorkCondition->setAirflowAngle(inAngle);
			if (m_CurrentCase != nullptr)
			{
				auto wcs = m_CurrentCase->getWorkConditions();
				for (auto k : wcs.keys())
				{
					wcs[k]->setAirflowAngle(inAngle);
				}
			}
		}
	}

	void C3fdSolveControlWidget::on_dsb_OutletPressure_editingFinished()
	{
		auto outPress = m_Ui->dsb_OutletPressure->value();
		if (m_CurrentWorkCondition != nullptr && !qFuzzyCompare(m_CurrentWorkCondition->getOutletPress(), outPress))
		{
			m_CurrentWorkCondition->setOutletPress(outPress);
		}
	}

	void C3fdSolveControlWidget::on_sb_StartRotationSpeed_editingFinished()
	{
		auto startSpeed = m_Ui->sb_StartRotationSpeed->value();
		if (m_CurrentWorkCondition != nullptr && (m_CurrentWorkCondition->getStartRotationSpeed() != startSpeed))
		{
			m_CurrentWorkCondition->setStartRotationSpeed(startSpeed);
		}
	}

	void C3fdSolveControlWidget::on_sb_IterativeSteps_editingFinished()
	{
		auto iterStep = m_Ui->sb_IterativeSteps->value();
		if (m_CurrentWorkCondition != nullptr && (m_CurrentWorkCondition->getInterativeStep() != iterStep))
		{
			m_CurrentWorkCondition->setInterativeStep(iterStep);
		}
	}

	void C3fdSolveControlWidget::on_pb_StopSolve_clicked()
	{
		if (m_Process.state() != QProcess::NotRunning)
		{
			m_Process.close();
		}
		else
		{
			QMessageBox::information(this, tr("Information"), tr("Slover has not been started!"));
		}
	}

	void C3fdSolveControlWidget::on_pb_Select_clicked()
	{
		QString mpiexec = QFileDialog::getOpenFileName(this, tr("Select File"), "", tr("mpiexec (mpiexec.exe)"));
		if (mpiexec.isNull() || mpiexec.isEmpty())
		{
			return;
		}
		else
		{
			m_Ui->lb_DisplayMpiPath->setText(mpiexec);
		}
	}

	void C3fdSolveControlWidget::on_pb_StartSolve_clicked()
	{
		if (m_CurrentWorkCondition == nullptr)
		{
			QMessageBox::critical(this, tr("Error Info"), tr("System Error!"));
			return;
		}
		if (QMessageBox::question(this, tr("Confirm Info"), tr("Start Calculation?"), QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok)
		{
			return;
		}

		auto workingConditionPath = m_Project->getCurrentProjectDir() + m_Project->getWorkingConditionDirName() + QDir::separator() + m_CurrentWorkCondition->getName() + QDir::separator();

		// 网格文件和叶片几何信息直接从mesh文件夹拷贝
		if (!copyMeshInputs(m_Project->getCurrentProjectDir() + m_Project->getMeshDirName() + QDir::separator(), workingConditionPath + m_Project->getSolverInputDirName() + QDir::separator()))
		{
			return;
		}

		// 求解控制文件不需修改，直接写入
		if (!generateControlInput(workingConditionPath + m_Project->getSolverInputDirName() + QDir::separator()))
		{
			return;
		}

		// 湍流模型文件不需修改，直接写入
		if (!generateTbmodelInput(workingConditionPath + m_Project->getSolverInputDirName() + QDir::separator()))
		{
			return;
		}

		// 控制参数及边界文件需要修改
		if (!generateBoundaryInput(workingConditionPath + m_Project->getSolverInputDirName() + QDir::separator()))
		{
			return;
		}

		if (!generatePerfCurveInput(workingConditionPath + m_Project->getSolverInputDirName() + QDir::separator()))
		{
			return;
		}

		// 写入报告数据
		if (m_CurrentCase != nullptr)
		{
			auto *reportData = m_CurrentCase->getReportData();
			if (reportData != nullptr)
			{
				reportData->setBoundaryModel(m_Ui->dsb_InletPressure->value(), m_Ui->dsb_InletTemperature->value(), m_Ui->dsb_OutletPressure->value(), m_Ui->dsb_RotationSpeed->value());
			}
		}

		// 调用SOLVER.exe求解计算
		QString solverEXE = m_Project->getSolverExeFilePath();
		if (!QFile::exists(solverEXE))
		{
			QMessageBox::critical(this, tr("Error Info"), tr("No found SOLVER.exe!"));
			return;
		}
#if 0
		// 求解程序调用方式  SOLVER.exe -input d:\INPUT -output d:\OUTPUT
		QString startProcess = QString("%1 -input %2 -output %3")
			.arg(solverEXE)
			.arg(workingConditionPath + m_Project->getSolverInputDirName() + QDir::separator())
			.arg(workingConditionPath + m_Project->getSolverOutputDirName() + QDir::separator());
#elif false
		QString startProcess = workingConditionPath + "SOLVER.bat";
		QFile solverBatFile(startProcess);
		if (solverBatFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
		{
			QTextStream solverBat(&solverBatFile);
			solverBat << solverEXE;
			solverBatFile.flush();
			solverBatFile.close();
		}
		m_Process.setWorkingDirectory(workingConditionPath);
#else
		QString solverBatContent = "";
		if (m_Ui->lb_DisplayMpiPath->text().isEmpty() || m_Ui->sb_Cores->value() < 2)
		{
			if (QMessageBox::question(this, tr("Confirm Info"), tr("No parallel Settings, continue?"), QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok)
			{
				return;
			}
			else
			{
				solverBatContent = solverEXE;
			}
		}
		else
		{
			solverBatContent = QString("%1 -n %2 %3").arg(m_Ui->lb_DisplayMpiPath->text()).arg(m_Ui->sb_Cores->value()).arg(solverEXE);
		}
		QString startProcess = workingConditionPath + "SOLVER.bat";
		QFile solverBatFile(startProcess);
		if (solverBatFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
		{
			QTextStream solverBat(&solverBatFile);
			solverBat << solverBatContent;
			solverBatFile.flush();
			solverBatFile.close();
		}
		m_Process.setWorkingDirectory(workingConditionPath);
#endif

		m_Process.start(startProcess);
	}

	void C3fdSolveControlWidget::processFinished(int, QProcess::ExitStatus exitStatus)
	{

		switch (exitStatus)
		{
		case QProcess::NormalExit:
			QMessageBox::information(this, tr("Information"), tr("Calculation completed!"));
			break;
		case QProcess::CrashExit:
			QMessageBox::critical(this, tr("Error Info"), tr("Solve Crashed!"));
			break;
		default:
			QMessageBox::information(this, tr("Information"), tr("Solve Stopped!"));
			break;
		}
	}

	void C3fdSolveControlWidget::readProcessOutput()
	{
		QString outputBuffer = QString::fromLocal8Bit(m_Process.readAll());
		emit updateLineChart(m_Project->getCurrentProjectDir() + m_Project->getWorkingConditionDirName() + QDir::separator() + m_CurrentWorkCondition->getName() + QDir::separator() + m_Project->getSolverOutputDirName() + QDir::separator() + m_Project->getSolverMonitorFileName());
		emit sendMessage(outputBuffer);
	}

	void C3fdSolveControlWidget::readAllStandardErrorSlot()
	{
		QString outputBuffer = QString::fromLocal8Bit(m_Process.readAllStandardError());
		emit sendMessage(outputBuffer);
	}
}